#ifndef     __RF_UART_H
#define     __RF_UART_H

#include "../rtos/message_queue.h"
#include "../rtos/event_flags.h"
#include "../utils/object.h"
#include "../utils/byte_view.h"
#include "../utils/alg.h"
#include "../utils/encode.h"

namespace driver {

class RfUart : private utils::NoCopyable {

public:
    static constexpr uint32_t RECV_BUF_SIZE = 64;
    static constexpr uint32_t WRITE_BUF_SIZE = 64;

    static constexpr uint32_t FLAG_WRITE_COMPLETE = 0x01;
    
    static constexpr uint8_t HEAD = 0xBB;
    static constexpr uint8_t TYPE_REQ = 0x00;
    static constexpr uint8_t TYPE_RES = 0x01;
    static constexpr uint8_t TYPE_NOTIFY = 0x02;
    static constexpr uint8_t END = 0x7E;

    RfUart();

    bool poll(utils::ByteView &bw, uint32_t timeout = osWaitForever) { return m_mq.poll(bw, timeout) == osOK; }

    template <typename... Ts>
    void write(uint8_t cmd, Ts&&... ts) {
        wait_write_complete();
        uint16_t len = utils::encode_all(m_write_buf + 5, std::forward<Ts>(ts)...);
        write_data(cmd, len);
    }

    void write_parameter(uint8_t cmd, const utils::ByteView &parameter) {
        wait_write_complete();
        memcpy(m_write_buf + 5, parameter.buf, parameter.len);
        write_data(cmd, parameter.len);
    }

    void on_recv_idle();
    void notify_write_complete() { m_flags.set_flags(FLAG_WRITE_COMPLETE); }
private:
    static void write_by_dma(const void *buf, uint8_t len);
    void write_data(uint8_t cmd, uint16_t arg_len);

    void wait_write_complete() { m_flags.wait_all_flags(FLAG_WRITE_COMPLETE); }

    uint8_t m_write_buf[WRITE_BUF_SIZE];
    uint8_t m_recv_buf[RECV_BUF_SIZE];
    uint32_t m_recv_index = 0;
    rtos::EventFlags m_flags;
    rtos::MessageQueue<utils::ByteView, 5> m_mq;
};

inline utils::Object<RfUart> rfUart;

}

#endif
